#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include "Estructuras.h"
#include <string.h>
#define modulo(x) ((x) < 0 ? - (x) : (x))

t_nodo * algoritmoSSTF(void);
t_nodo * algoritmoCSCAN(void);
t_nodo * busquedaAlgoritmoCSCAN (void);
int procesarDato(char *);
void inicializarCHS(void);
void incializarCola(void);
void * AbreDiscoEnMemoria(char *);
void leerArchivoConfiguracion(const char *);
t_nodo * busquedaAlgoritmoCSCAN (void);
t_nodo * busquedaAlgoritmoSSTF (void);
void meterEnCola(long , char * , unsigned char , long, unsigned int );
int sacarDeCola(void);
t_nodo * algoritmoDePlanificacion (void);



void inicializarCHS(void) {
    CHS.cabezal = 0;
    CHS.pista = 0;
    CHS.sector = 0;
}

void incializarCola(void){
        colaFte = NULL;
        colaFin = NULL;
}

//mappea el disco en memoria
void * AbreDiscoEnMemoria(char * rutaArchivo){

    int descriptorDisco;
    void * map;
    struct stat statbuf;

    descriptorDisco = open(rutaArchivo, O_RDWR);
    fstat(descriptorDisco, &statbuf);

    tamanoDisco = statbuf.st_size;

    map = mmap(0, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, descriptorDisco, 0);

    posix_madvise(map, statbuf.st_size, POSIX_MADV_RANDOM);

    return map;
}//fin mappear disco



//Leer archivo configuracion

int procesarDato(char * linea){

  char palabra[20];
  char dato[9999] = {' '};
  int i = 0, j = 0;

  while(linea[i] != ' '){
        palabra[i] = linea [i];
        i++;
        }

  palabra[i++] = 0;

  while(linea[i] != '\n'){
      dato[j] = linea[i];
      i++;
      j++;
  }

  dato[j] = 0;

if (strcmp(palabra,"Modoini") == 0 ) {
      modoInicio = atoi(dato);
}
if (strcmp(palabra,"Flaglog") == 0 ) {
      FlagLog = atoi(dato);
}
if(strcmp(palabra,"Iddisco") == 0 ){
      IdDisco = atoi(dato);
}
if (strcmp(palabra,"Cantsecporpis") == 0 ) {
      cantSecPorPista = atoi(dato);
}
if(strcmp(palabra,"Patharclog") == 0 ){
      strcpy(pathArchivoLogueo,dato);
}
  if (strcmp(palabra,"Pista") == 0 ) {
      cantidadPistas = atoi(dato);
}
  if (strcmp(palabra,"Cabezal") == 0 ) {
      cantidadCabezales = atoi(dato);
}
 if(strcmp(palabra,"Alg") == 0){
      strcpy(Algoritmo,dato);
}
  if (strcmp(palabra,"Tlect") == 0) {
    T_Lectura  = atoi(dato);
}
  if (strcmp(palabra,"Tescr") == 0) {
    T_Escritura = atoi(dato);
}
  if(strcmp(palabra,"Path") == 0 ){
      strcpy(pathSocketUnix,dato);
}
if(strcmp(palabra,"RPM")== 0 )
    RPM = atoi(dato);
if(strcmp(palabra, "TSal") == 0)
    T_SaltoPista = atoi(dato);

    return 0;
}

void leerArchivoConfiguracion(const char * path){

     FILE *archivo;
            char  linea[30];



            archivo = fopen(path,"r");

            if (archivo == NULL)

                    printf("\nError de apertura del archivo. \n\n");


                while (feof(archivo) == 0)
                {

                fgets(linea,30,archivo);

                    procesarDato(linea);


                }
		T_SaltoSector = 60000 / (cantSecPorPista * RPM);


 }
//Fin leer archivo configuracion

t_nodo * algoritmoDePlanificacion (void){

        t_nodo * nodoAux;
        if (strcmp(Algoritmo, "SSTF") == 0){
                nodoAux =  algoritmoSSTF ();
        }
        if (strcmp(Algoritmo, "CSCAN") == 0){
                nodoAux = algoritmoCSCAN ();
        }
        return nodoAux;
}



//Algoritmo de planificacion con inanicion

 t_nodo * algoritmoSSTF(void){

     long minValue = 2147483647;
     t_nodo * ptr = colaFte;
     t_nodo * ptrAux;
     long distancia;



     while (ptr) {

        distancia = modulo((signed int) ((ptr->pista) - CHS.pista));

         if(distancia  < minValue){
             minValue = distancia;
             ptrAux = ptr;
         }
             ptr = ptr->siguiente;

     }

         ptr = colaFte;

         if (ptrAux != colaFte)
                while ((ptr->siguiente) != ptrAux)
                        ptr = ptr->siguiente;




         if (ptrAux == colaFte){
             colaFte = (ptrAux->siguiente);
             if (!(colaFte))
                colaFin = NULL;
         } else if ((ptrAux->siguiente) == NULL){
             ptr->siguiente = NULL;
             colaFin = ptr;
         } else
                ptr->siguiente = ptrAux->siguiente;




     return ptrAux;
 }

 t_nodo * busquedaAlgoritmoSSTF (void){

        long minValue = 2147483647;
            t_nodo * ptr = colaFte;
            t_nodo * ptrAux;
            long distancia;



            while (ptr) {

                distancia = modulo((signed int) ((ptr->pista) - CHS.pista));

                if(distancia  < minValue){
                    minValue = distancia;
                    ptrAux = ptr;
                }
                    ptr = ptr->siguiente;

            }

                ptr = colaFte;

                if (ptrAux != colaFte)
                        while ((ptr->siguiente) != ptrAux)
                                ptr = ptr->siguiente;

                return  ptrAux;

 }
//fin algoritmo SSTF
//Algoritmo de planificacion sin inanicion

 t_nodo * algoritmoCSCAN(void){

   t_nodo * ptr, * ptrAnt = NULL;
   t_nodo * ptrMinTodos   = NULL;
   t_nodo * ptrMinMayores = NULL;
   t_nodo * ptrMinTodosAnt =  NULL;
   t_nodo * ptrMinMayoresAnt = NULL;
   long minTodos   = 2147483647;
   long minMayores = 2147483647;

   for(ptr = colaFte; ptr; ptrAnt = ptr, ptr = ptr -> siguiente){
          if (ptr->pista < minTodos) {
                  minTodos = ptr->pista;
                  ptrMinTodos = ptr;
                  ptrMinTodosAnt = ptrAnt;
          }
          if (ptr->pista < CHS.pista) continue;
          if (ptr->pista < minMayores) {
                  minMayores = ptr->pista;
                  ptrMinMayores = ptr;
                  ptrMinMayoresAnt = ptrAnt;
          }
  }

  if (ptrMinMayores) {
          ptr = ptrMinMayores;
          ptrAnt = ptrMinMayoresAnt;
  } else {
          ptr = ptrMinTodos;
          ptrAnt = ptrMinTodosAnt;
  }

  if (ptrAnt == NULL) {
          colaFte = ptr->siguiente;
          if (colaFte == NULL) colaFin = NULL;
  } else {
          ptrAnt -> siguiente = ptr -> siguiente;
          if (ptr -> siguiente == NULL) colaFin = ptrAnt;
  }

  return ptr;

  }

 t_nodo * busquedaAlgoritmoCSCAN (void){

   t_nodo * ptr = NULL;
   t_nodo * ptrMinTodos   = NULL;
   t_nodo * ptrMinMayores = NULL;
   long minTodos   = 2147483647;
   long minMayores = 2147483647;

   for(ptr = colaFte; ptr; ptr = ptr -> siguiente){
          if (ptr->pista < minTodos) {
                  minTodos = ptr->pista;
                  ptrMinTodos = ptr;
          }
          if (ptr->pista < CHS.pista) continue;
          if (ptr->pista < minMayores) {
                  minMayores = ptr->pista;
                  ptrMinMayores = ptr;
          }
  }

  if (ptrMinMayores) ptr = ptrMinMayores; else ptr = ptrMinTodos;

  return ptr;
 }

//fin algoritmo cscan

 void meterEnCola(long nroSector, char * datosSector, unsigned char tipo, long pista, unsigned int remitente) {

      t_nodo * nuevoNodo = malloc(sizeof(t_nodo));



      switch(tipo){
      //tipo 0 lectura
      case 0:
          nuevoNodo->datos = NULL;
          nuevoNodo->tipo = 0;
          break;
      //tipo 1 lectura
      case 1:
          nuevoNodo->datos = malloc(512);
          memcpy((nuevoNodo -> datos), datosSector, 512);
          nuevoNodo->tipo = 1;
          break;
      //tipo 2 trace
      case 2:
          nuevoNodo->tipo = 2;
          nuevoNodo->datos = NULL;
          break;
      }

      nuevoNodo->nroSector = nroSector;
      nuevoNodo->pista = pista;
      nuevoNodo->remitente = remitente;
      nuevoNodo -> siguiente = NULL;
      if (colaFin)
        colaFin->siguiente = nuevoNodo;
      else
        colaFte = nuevoNodo;
        colaFin = nuevoNodo;
 }

 int sacarDeCola(void) {
      t_nodo * nodo = colaFte;
      int valor;
      if (!nodo) return 0;
      colaFte = nodo -> siguiente;
      if (!(colaFte)) colaFin = 0;
      valor = nodo->nroSector;
      free(nodo);
      return valor;
 }
